﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DevExpress.XtraEditors.Controls;
using ProgNetComponents.Data.SqlCe;
using System.Data;
using ProgNetComponents.Classes;
using System.Diagnostics;
using ProgNetComponentsDx.Browsers;
using ProgNetComponentsDx.Options;
using System.Windows.Forms;
using System.Threading.Tasks;

namespace BuildHelper.Setup.Brancze
{
    public static class BranczeTools
    {
        public static event ChangingEventHandler ActiveBranchChanging;
        public static event EventHandler ActiveBranchChanged;
        private static BranczeDataSet branczDs = new BranczeDataSet();
        private static NamedObject parameter = new NamedObject("@NAZWA", "");

        private static string _ActiveBranch;
        public static string ActiveBranch
        {
            get { return _ActiveBranch; }
            set
            {
                if (_ActiveBranch != value)
                {
                    ChangingEventArgs e = new ChangingEventArgs(_ActiveBranch, value, false);
                    if (ActiveBranchChanging != null)
                        ActiveBranchChanging(null, e);
                    if (!e.Cancel)
                    {
                        _ActiveBranch = value;
                        if (ActiveBranchChanged != null)
                            ActiveBranchChanged(null, EventArgs.Empty);
                        SetEnvVariables();
                        OptionCache.SetOptionValue(Init.InitFormOptionNames.Niewidoczne.OstatniBrancz, value, true);
                    }
                }
            }
        }
        private static void UpdateCurrentDB()
        {
        }
        private static Process SetEnvVariablesProcess;
        private static void Setx(string var, string value)
        {
            Task t = Task.Factory.StartNew(() =>
            {
                using (Process process = new Process())
                {
                    ProcessStartInfo psi = new ProcessStartInfo("setx.exe", " /M " + var + " " + value);
                    psi.CreateNoWindow = true;
                    psi.UseShellExecute = false;
                    psi.RedirectStandardError = true;
                    psi.RedirectStandardInput = true;
                    psi.RedirectStandardOutput = true;
                    psi.WindowStyle = ProcessWindowStyle.Hidden;
                    process.StartInfo = psi;
                    process.Start();
                    process.WaitForExit();
                    process.Dispose();
                }
            });
        }
        public static void SetEnvVariables(bool waitForExit = false, List<string> toDelete = null)
        {
            while (SetEnvVariablesProcess != null)
            {
                Application.DoEvents();
                if (Program.IsExit)
                    return;
            }

            parameter.Value = ActiveBranch;
            branczDs.Clear();
            branczDs.AcceptChanges();
            SqlCeDataManager m = Manager;
            m.FillDataSet(branczDs, parameter);
            m.Dispose();

            if (branczDs.STP_BRANCZE.Rows.Count == 1)
            {
                Dictionary<string, string> d = GetZmienneBrancza(ActiveBranch);
                Process current = Process.GetCurrentProcess();
                Process explorer = null;
                SetEnvVariablesProcess = GlobalTools.CreateCMDProcess(SetEnvVariables_Data);

                if (OptionCache.GetOptionBoolValue(Init.InitFormOptionNames.Brancze.ZmieniajZmienneDlaExplorera))
                {
                    Process[] explorers = Process.GetProcessesByName("explorer");
                    if (explorers != null && explorers.Length == 1 && explorers[0].StartInfo != null)
                        explorer = explorers[0];
                }

                string val = "";
                
                string globalDrive = OptionCache.GetOptionStringValue(Init.InitFormOptionNames.Brancze.ActiveBranczDrive);
                if (globalDrive.IsNotNull())
                {
                    string katalog = branczDs.STP_BRANCZE[0]["STP_BR_KATALOG"].AsString().TrimEnd('\\');
                    SubstDrive(globalDrive, katalog);
                }

                foreach (KeyValuePair<string, string> kvp in d)
                {
                    GlobalTools.ProcessTools.SetEnvVariable(current, kvp.Key, kvp.Value);
                    System.Environment.SetEnvironmentVariable(kvp.Key, kvp.Value, EnvironmentVariableTarget.Process);
                    if (OptionCache.GetOptionBoolValue(Init.InitFormOptionNames.Brancze.ZmieniajZmienneDlaExplorera))
                    {
                        if (explorer != null)
                            GlobalTools.ProcessTools.SetEnvVariable(explorer, kvp.Key, kvp.Value);
                        val = kvp.Value;
                        if (val.XMatch("\\s+") || val.IsNull())
                            val = val.AddDoubleQuotes();
                        Setx(kvp.Key, val);
                    }
                }
                if (toDelete != null)
                {
                    foreach (string env in toDelete)
                    {
                        GlobalTools.ProcessTools.SetEnvVariable(current, env, null);
                        System.Environment.SetEnvironmentVariable(env, null, EnvironmentVariableTarget.Process);
                        if (OptionCache.GetOptionBoolValue(Init.InitFormOptionNames.Brancze.ZmieniajZmienneDlaExplorera))
                        {
                            if (explorer != null)
                                GlobalTools.ProcessTools.SetEnvVariable(explorer, env, null);
                            Setx(env, "".AddDoubleQuotes());
                        }
                    }
                }
                
                SetEnvVariablesProcess.Execute("echo exit");
            }
            else
            {
                Exception ex = new Exception("Nie można określić brancza (" + branczDs.STP_BRANCZE.Rows.Count + ").");
                ex.Log();
            }
            if (waitForExit)
            {
                while (true)
                {
                    Application.DoEvents();
                    System.Threading.Thread.Sleep(10);
                    if (SetEnvVariablesProcess == null)
                    {
                        break;
                    }
                }
            }
        }
        public static void DeleteEnvVariables(List<string> vars)
        {

        }
        private static void SetEnvVariables_Data(object sender, DataReceivedEventArgs e)
        {
            if (e.Data.AsString() == "exit")
            {
                try
                {
                    SetEnvVariablesProcess.KillProcessTree();
                    SetEnvVariablesProcess.Dispose();
                }
                catch { }
                SetEnvVariablesProcess = null;
            }
        }
        private static SqlCeDataManager Manager
        {
            get
            {
                SqlCeDataManager _Manager;
                _Manager = new SqlCeDataManager();
                _Manager.AutoLogExceptions = true;
                _Manager.AddTableDef(branczDs.STP_BRANCZE, "SELECT * FROM STP_BRANCZE WHERE STP_BR_NAZWA = @NAZWA");
                _Manager.AddTableDef(branczDs.STP_ZMIENNE, "SELECT * FROM STP_ZMIENNE WHERE STP_ZM_BRANCZ = @NAZWA OR STP_ZM_BRANCZ IS NULL ORDER BY STP_ZM_BRANCZ");
                return _Manager;
            }
        }
        public static Dictionary<string, string> GetZmienneBrancza(String brancz, bool noGlobalNdrive)
        {
            BranczeDataSet ds = null;
            Dictionary<string, string> dic = null;
            if (brancz == ActiveBranch)
            {
                ds = branczDs;
            }
            else
            {
                ds = branczDs.Clone() as BranczeDataSet;
                parameter.Value = brancz;
                SqlCeDataManager m = Manager;
                m.FillDataSet(ds, parameter);
                m.Dispose();
            }
            dic = GetZmienneBrancza(ds.STP_ZMIENNE);

            if (ds.STP_BRANCZE.Rows.Count == 1)
            {
                string NDRIVE = "";
                string NSDIR = "";
                string NDIR = "";
                if (!noGlobalNdrive &&  OptionCache.GetOptionStringValue(Init.InitFormOptionNames.Brancze.TypNdrive) == "G")
                {
                    NDRIVE = OptionCache.GetOptionStringValue(Init.InitFormOptionNames.Brancze.ActiveBranczDrive) + ":";
                    NSDIR = NDRIVE + "\\nd_src";
                    NDIR = NDRIVE + "\\nd_r";
                }
                else
                {
                    string katalog = ds.STP_BRANCZE[0]["STP_BR_KATALOG"].AsString().TrimEnd('\\');
                    NDRIVE = katalog.SubstringSafe(0, 2);
                    NSDIR = katalog + "\\nd_src";
                    NDIR = katalog + "\\nd_r";
                }
                dic["NDRIVE"]= NDRIVE;
                dic["NDIR"] = NDIR;
                dic["NSDIR"] = NSDIR;
            }
            return dic;
        }
        public static Dictionary<string, string> GetZmienneBrancza(String brancz)
        {
            return GetZmienneBrancza(brancz, brancz != Setup.Brancze.BranczeTools.ActiveBranch);
        }
        private static Dictionary<string, string> GetZmienneBrancza(DataTable dt)
        {
            Dictionary<string, string> dic = new Dictionary<string, string>();
            DataRow[] rows = dt.Select(null, "STP_ZM_BRANCZ");
            foreach (DataRow r in rows)
            {
                if (dic.ContainsKey(r["STP_ZM_NAZWA"].AsString()))
                    dic.Remove(r["STP_ZM_NAZWA"].AsString());
                dic.Add(r["STP_ZM_NAZWA"].AsString(), r["STP_ZM_WARTOSC"].AsString());
            }
            return dic;
        }

        public static string ActiveBranczDir
        {
            get
            {
                if (branczDs.STP_BRANCZE.Rows.Count == 1)
                    return branczDs.STP_BRANCZE[0]["STP_BR_KATALOG"].AsString();
                return "";
            }
        }

        public static void SubstDrive(string drive, string dir, bool withTask = true)
        {
            var cmd = GlobalTools.CreateCMDProcess(null);
            try
            {
                cmd.Execute("subst /D " + drive + ":");
                System.Threading.Thread.Sleep(50);
                cmd.Execute("subst " + drive + ": " + dir.AddDoubleQuotes());
                System.Threading.Thread.Sleep(50);
                cmd.CallExit();
                cmd.WaitForExit();
                cmd.Dispose();
                cmd = null;
                if (withTask)
                {
                    SubstClass s = new SubstClass(drive,dir);
                    s.Start();
                }
            }
            catch { }
        }
        private class SubstClass
        {
            public SubstClass(string drive, string dir)
            {
                drives[drive] = dir;
                this.drive = drive;
            }
            private string drive;

            private static Dictionary<string, string> drives = new Dictionary<string, string>();

            private static object lockBrowser = new object();
            public void Start()
            {
                Task t = Task.Factory.StartNew(WaitForChange);
            }
            private void WaitForChange()
            {
                for (int i = 1; i < 20; i++)
                {
                    System.Threading.Thread.Sleep(500 * i);

                    DataTable dt = null;
                    lock (lockBrowser)
                    {
                        dt = BrowserCache.GetBrowserData(Init.InitFormBrowserNames.Statyczne.SubstedDrives, true);
                    }
                    string dir = "";
                    if (drives.ContainsKey(drive))
                        dir = drives[drive];
                    if (dt != null)
                    {
                        if (drives.ContainsKey(drive))
                        {
                            DataRow r = dt.SelectFirstRow("DRIVE = " + drive.EscapeSql());
                            if (r != null)
                            {
                                if (r["KATALOG"].AsString().ToLower() == dir.AsString().ToLower())
                                {
                                    drives.Remove(drive);
                                    return;
                                }
                            }
                        }
                    }
                    if (dir.IsNotNullOrEmpty())
                        SubstDrive(drive, dir, false);
                }
            }
        }

        public static void UnSubstDrive(string drive)
        {
             var cmd = GlobalTools.CreateCMDProcess(null);
             try
             {
                 cmd.Execute("subst /D " + drive + ":");
                 System.Threading.Thread.Sleep(50);
                 cmd.CallExit();
                 cmd.WaitForExit();
                 cmd.Dispose();
                 cmd = null;
             }
             catch { }
        }
    }
}
